/*****************************************************************************************/
/* ECSE 426 - Microprocessor - Fall 2009
/* Lab Experiment 2 - UART Control
/* KEYPAD.C
/* @author: Danny Wu - 260238209 - B.Comp.Eng
/* @author: Han-Sheng Chin - 260209715 - B.Elec.Eng
/* @version: 09.09.18.1304 
/****************************************************************************************/
#include <msp430x14x.h>
//#include <msp430x12x.h>
#include <stdlib.h>
#include <keypad.h>
int ERROR_FLAG = 1;
int noKey = 0x1;
int noMatch = 0x2;
int keyHex;


void initKeypad (void){
  int key = 0;
  //initialize keyboard
  P1DIR &= 0xF1;                // input when low:0000 1110 (P1.1,1.2,1.3)
  P3DIR |= 0x0F;                // output when high: 0000 00000 (P3.0, 3.1,3.2,3.3)
  
  P1IFG = 0x00;                 // no interrupt flag
  P1IES = 0x00;
  P1IE = 0x0E;                  //enable interrupt for port1

  BCSCTL1 = 0;                 // RSEL = 0 and DCO = 3

  //while(key == 0){
    //setForPress();             // set the wait for keypress
    //_BIS_SR(LPM0_bits);        // wait for keypress, originally LPM4
    //debounce();                // call debounce delay
    //keyScan();                 // scan keypad 
    //if((ERROR_FLAG&noKey) == 0){   // test if no key was depressed 
    //key=keyLookup();             // lookup key value
    //if(key != 0) return key;
      //waitForRelease();        // wait for key to be released
    //}//end if
  //}//end while
  return ;
}//end main

/**
 * setForPress
 **/
void setForPress(void){
  P3OUT |= 0x0F;                      // enable keypad (for P3.0,3.1,3.2,3.3)
  P1IES &= 0xF1;                      // low to high interrupts (for P1.1,1.2,1.3)
  P1IFG =  0x0;                       // clear pending flags
  P1IE = BIT1 + BIT2 + BIT3;          // enable interrupts 

  ERROR_FLAG = 0;                     // clear error flag
  return;
}//end setForPress

/**
 * Debounce
 *
 **/
void debounce(void){
  TACTL = TASSEL1 + TACLR;           // smclk, clear Timer A
  TACCTL0 = CCIE;                    // enable CCR0 interrupt
  TACCR0 = 5125;                     // 40ms delay, this is a count divided by bit rate = 40ms
  TACTL = MC0;                       // value of (0x0010)  /* Timer A mode control 0 */
  _BIS_SR(LPM0_bits);                // wait for keypress, sleep during debounce delay
  return;
}//end debounce

/**
 * Keyscan
 **/
void keyScan(void){
  int keyMask = 1;                   // init scan mask
  int loopCount = 4;                 // init loop counter
  int temp;                          // temp variable
  keyHex = 0;                        // clear register

  P1OUT &= 0xF1;                     // clear column bits in P1OUT reg
  while (loopCount > 0 && keyHex == 0){
    //P1OUT &= 0xF1;                   // clear column bits in P1OUT reg
    P3OUT &= 0xF0;                   // stop driving rows
    P1OUT &= 0xF1;                   // clear column bits in P1OUT reg
    P3OUT = keyMask;                 // drive row, key mask = 1, 2, 4, 8
    if (P1IN & (BIT1 + BIT2 + BIT3) != 0){ //verify if there's a signal at 1110 for PIN1

        keyHex += keyMask;             // Record the row that sent the signal 
        temp = P1IN & 0x0E;            // Dummy records the colums
        temp = temp<<4;                // Shift everything to the upper 0x
        keyHex += temp;                // Record in keyhex

    }//end if
    //change to a new mask
    keyMask = keyMask <<1;           //rotate the mask
    loopCount--;                     //dec counter    
  }//end while

  //test for double keys, if destination of keyHex is not valid, exit loop
  if (keyMask == 0){
   ERROR_FLAG |= noKey;
  }//endif
  P3OUT |= 0x0F;                     // drive the keys again

  return;
}//end keyScan

/**
 * keyLookup
 **/
int keyLookup(void){
    int keyVal;
    switch(keyHex){
      case 0x48:   //4 8
        keyVal = 0; break;
      case 0x21:   //2 1
        keyVal = 1;break;
      case 0x41:   //4 1
        keyVal = 2; break;
      case 0x81:   //8 1
        keyVal = 3; break;
      case 0x22:   //2 2
        keyVal = 4; break;
      case 0x42:   //4 2 
        keyVal = 5; break;
      case 0x82:   //8 2 
        keyVal = 6; break;
      case 0x24:   //2 4 
        keyVal = 7; break;
      case 0x44:   //4 4 
        keyVal = 8; break;
      case 0x84:   //8 4 
        keyVal = 9;break;
      case 0x28:   //2 8 
        keyVal = 10; break;
      case 0x88:   //8 8 
        keyVal = 11; break;
      default:     //default value
        keyVal = 12;break;
      }//end switch    
  return keyVal;
}//end keyLookup

/**
 * WaitForRelease
 **/
void waitForRelease(void){
//  int rowCtr = 1; //row counter
//  keyHex &= 0xF;
//  keyHex = (keyHex >> 1);
//  if(keyHex > 0)
//    keyHex += 0x8;
//  
  P1DIR |= 0x0E;                      // set the direction for p1.1 to p1.3
  P1OUT &= 0xF1;                      // bleed off charge and avoid errorneous reads

  P1DIR &= 0xF1;                      // set column back to input
  P1IES |= 0x0E;                      // high to low interrupts (for P1.1,1.2,1.3)
  _BIS_SR(LPM4_bits);                 // sleeping waiting for release
  debounce();
  keyScan();
  if(ERROR_FLAG != noKey){   // test if no key was depressed 
    waitForRelease();        // wait for key to be released
  }//end if

  ERROR_FLAG = 0;            //clear flag
  return;
}//end waitForRelease




/**********************************************************/
/* set an interrupt for timer A
/**********************************************************/
int setP1ISR (void) __interrupt[PORT1_VECTOR]{
  int i=0;
  _DINT();
  TACTL = TASSEL1+TACLR;
  TACCTL0 = CCIE;
  //TACCR0 = 5125;       // set the count for 40ms
  //TACTL |= 0x10;       // timer a control
  for(;i<1000;i++);
  keyScan();
  i = keyLookup();

  P1IFG = 0x0;         // set the flag
  _EINT();
  return i;
}//end setP1ISR


/**********************************************************/
/* Timer A is set to end at 40ms, after this timer, 
/* it will stop and it will sample the receiving pin
/* input from P1.X
/**********************************************************/
void setTimerA (void) __interrupt[TIMERA0_VECTOR]{
   TACTL = TACLR;
   TACCTL0 = 0;
   keyScan();
   P1IFG = 0x0;
   ERROR_FLAG = 1;            // key was pressed
   return;
}// end setTimerA
